/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package commons.util;

import java.text.Format;

/**
 * @author Susanta Tewari
 * @since Dec 23, 2011
 */
public class PrintUtil {

    /**
     * Uses {@code toString()} method or a provided format to print elements of a 2D.
     *
     * @param objs2D
     * @param horiCellPadding
     * @param vertCellPadding
     * @param format the format to be used or {@code null} to indicate none be used
     * @return
     */
    public static String print2D(Object[][] objs2D, int horiCellPadding, int vertCellPadding,
                                 Format format) {

        StringBuilder strBuilder = new StringBuilder();


        // max lengths
        int[] maxs = new int[objs2D[0].length];

        for (int i1 = 0; i1 < maxs.length; i1++) {

            final Object[] col = ArrayUtil.getColumn(objs2D, i1);
            int maxStrLen = (format == null) ? getMaxStringLen(col) : getMaxStringLen(col, format);

            maxs[i1] = maxStrLen;
        }

        // print rows
        for (int i1 = 0; i1 < objs2D.length - 1; i1++) {

            final Object[] row = objs2D[i1];

            strBuilder.append(printRow(row, horiCellPadding, maxs, format));

            for (int i2 = 0; i2 < vertCellPadding; i2++) {
                strBuilder.append("\n");
            }
        }

        strBuilder.append(printRow(objs2D[objs2D.length - 1], horiCellPadding, maxs, format));
        strBuilder.append("\n");

        return strBuilder.toString();
    }

    /**
     * Method description
     *
     *
     * @param objs
     * @param horiCellPadding
     * @param maxs
     * @param format
     *
     * @return
     */
    public static String printRow(Object[] objs, int horiCellPadding, int[] maxs,
                                  Format format) {

        StringBuilder strBuilder = new StringBuilder();

        for (int i = 0; i < objs.length - 1; i++) {

            String objStr = (format == null) ? objs[i].toString() : format.format(objs[i]);

            strBuilder.append(objStr).append(getPadding(horiCellPadding
                    + (maxs[i] - objStr.length())));
        }

        String lastStr = (format == null)
                         ? objs[objs.length - 1].toString() : format.format(objs[objs.length - 1]);

        strBuilder.append(lastStr).append(getPadding((maxs[maxs.length-1] - lastStr.length())));

        return strBuilder.toString();
    }

    /**
     * Method description
     *
     *
     * @param objs2D
     *
     * @return
     */
    private static int getMaxStringLen(Object[][] objs2D) {

        int maxStrLen = 0;

        for (Object[] objRow : objs2D) {

            for (Object obj : objRow) {
                maxStrLen = Math.max(maxStrLen, obj.toString().length());
            }
        }

        return maxStrLen;
    }

    private static int getMaxStringLen(Object[] objs1D) {

        int maxStrLen = 0;

        for (Object obj : objs1D) {
            maxStrLen = Math.max(maxStrLen, obj.toString().length());
        }

        return maxStrLen;
    }

    /**
     * Method description
     *
     *
     * @param objs2D
     * @param format
     *
     * @return
     */
    private static int getMaxStringLen(Object[][] objs2D, Format format) {

        int maxStrLen = 0;

        for (Object[] objRow : objs2D) {

            for (Object obj : objRow) {
                maxStrLen = Math.max(maxStrLen, format.format(obj).length());
            }
        }

        return maxStrLen;
    }

    private static int getMaxStringLen(Object[] objs1D, Format format) {

        int maxStrLen = 0;

        for (Object obj : objs1D) {
            maxStrLen = Math.max(maxStrLen, format.format(obj).length());
        }

        return maxStrLen;
    }

    /**
     * Method description
     *
     *
     * @param charCount
     *
     * @return
     */
    private static String getPadding(int charCount) {

        String pad = "";

        for (int i = 0; i < charCount; i++) {
            pad += " ";
        }

        return pad;
    }
}
